﻿#region Copyright RenGuiYou. All rights reserved.
//=====================================================
// NeatlyFrameWork
// Author:      RenGuiyou
// Feedback: 	mailto:750539605@qq.com
//=====================================================
#endregion

using System;
using UnityEngine;

public class NMathf
{
    #region Const Property
    public const float PI = 3.14159274f;
    public const float Infinity = float.PositiveInfinity;
    public const float NegativeInfinity = float.NegativeInfinity;
    public const float Deg2Rad = 0.0174532924f;
    public const float Rad2Deg = 57.29578f;
    #endregion

    #region Trigonometric
    public static float Sin(float f)
    {
        return (float)Math.Sin(f);
    }

    public static float Cos(float f)
    {
        return (float)Math.Cos(f);
    }

    public static float Tan(float f)
    {
        return (float)Math.Tan(f);
    }

    public static float Asin(float f)
    {
        return (float)Math.Asin(f);
    }

    public static float Acos(float f)
    {
        return (float)Math.Acos(f);
    }

    public static float Atan(float f)
    {
        return (float)Math.Atan(f);
    }

    public static float Atan2(float y, float x)
    {
        return (float)Math.Atan2(y, x);
    }
    #endregion

    #region Min&Max
    public static float Min(float a, float b)
    {
        return (a >= b) ? b : a;
    }

    public static float Min(params float[] values)
    {
        int num = values.Length;
        float num2 = values[0];
        for (int i = 1; i < num; i++)
        {
            if (values[i] < num2)
            {
                num2 = values[i];
            }
        }
        return num2;
    }

    public static int Min(int a, int b)
    {
        return (a >= b) ? b : a;
    }

    public static int Min(params int[] values)
    {
        int num = values.Length;
        int num2 = values[0];
        for (int i = 1; i < num; i++)
        {
            if (values[i] < num2)
            {
                num2 = values[i];
            }
        }
        return num2;
    }

    public static float Max(float a, float b)
    {
        return (a <= b) ? b : a;
    }

    public static float Max(params float[] values)
    {
        int num = values.Length;
        float num2 = values[0];
        for (int i = 1; i < num; i++)
        {
            if (values[i] > num2)
            {
                num2 = values[i];
            }
        }
        return num2;
    }

    public static int Max(int a, int b)
    {
        return (a <= b) ? b : a;
    }

    public static int Max(params int[] values)
    {
        int num = values.Length;
        int num2 = values[0];
        for (int i = 1; i < num; i++)
        {
            if (values[i] > num2)
            {
                num2 = values[i];
            }
        }
        return num2;
    }
    #endregion

    #region Simple

    public static float Sqrt(float f)
    {
        return (float) Math.Sqrt(f);
    }
    
    public static float Pow(float f, float p)
    {
        return (float)Math.Pow(f, p);
    }

    public static float Exp(float power)
    {
        return (float)Math.Exp(power);
    }

    public static float Log(float f, float p)
    {
        return (float)Math.Log(f, p);
    }

    public static float Log(float f)
    {
        return (float)Math.Log(f);
    }

    public static float Log10(float f)
    {
        return (float)Math.Log10(f);
    }

    public static float Ceil(float f)
    {
        return (float)Math.Ceiling(f);
    }

    public static float Floor(float f)
    {
        return (float)Math.Floor(f);
    }

    public static float Round(float f)
    {
        return (float)Math.Round(f);
    }

    public static int CeilToInt(float f)
    {
        return (int)Math.Ceiling(f);
    }

    public static int FloorToInt(float f)
    {
        return (int)Math.Floor(f);
    }

    public static int RoundToInt(float f)
    {
        return (int)Math.Round(f);
    }

    public static float Sign(float f)
    {
        return (f < 0f) ? -1f : 1f;
    }

    public static float Clamp(float value, float min, float max)
    {
        if (value < min)
        {
            value = min;
        }
        else if (value > max)
        {
            value = max;
        }
        return value;
    }

    public static int Clamp(int value, int min, int max)
    {
        if (value < min)
        {
            value = min;
        }
        else if (value > max)
        {
            value = max;
        }
        return value;
    }

    public static float Clamp01(float value)
    {
        if (value < 0f)
        {
            return 0f;
        }
        if (value > 1f)
        {
            return 1f;
        }
        return value;
    }
    #endregion

    #region Lerp
    public static float Lerp(float a, float b, float t)
    {
        t = Clamp01(t);
        return (b - a) * t + a;
    }

    public static float Lerp(float a, float b, float delta, float total)
    {
        return Lerp(a, b, delta / total);
    }

    public static double Lerp(double a, double b, float t)
    {
        t = Clamp01(t);
        return (b - a) * t + a;
    }

    public static double Lerp(double a, double b, float delta, float total)
    {
        return Lerp(a, b, delta / total);
    }

    public static Vector3 Lerp(Vector3 a, Vector3 b, float t)
    {
        return new Vector3(Lerp(a.x, b.x, t), Lerp(a.y, b.y, t), Lerp(a.z, b.z, t));
    }

    public static Vector3 Lerp(Vector3 a, Vector3 b, float delta, float total)
    {
        return Lerp(a, b, delta / total);
    }

    public static Color Lerp(Color a, Color b, float t)
    {
        t = Clamp01(t);
        return new Color(Lerp(a.r, b.r, t), Lerp(a.g, b.g, t), Lerp(a.b, b.b, t), Lerp(a.a, b.a, t));
    }

    public static Color Lerp(Color a, Color b, float delta, float total)
    {
        return Color.Lerp(a, b, delta / total);
    }

    public static float LerpUnclamped(float a, float b, float delta, float total)
    {
        return LerpUnclamped(a,b,delta/total);
    }

    public static float LerpUnclamped(float a, float b, float t)
    {
        return a + (b - a) * t;
    }

    public static float LerpAngle(float a, float b, float t)
    {
        float num = Repeat(b - a, 360f);
        if (num > 180f)
        {
            num -= 360f;
        }
        return a + num * Clamp01(t);
    }

    public static Vector3 LerpAngle(Vector3 a, Vector3 b, float t)
    {
        return new Vector3(LerpAngle(a.x, b.x, t), LerpAngle(a.y, b.y, t), LerpAngle(a.z, b.z, t));
    }

    public static Vector3 LerpAngle(Vector3 a, Vector3 b, float delta, float total)
    {
        return LerpAngle(a, b, delta / total);
    }

    #endregion

    #region Extra
    public static float Repeat(float t, float length)
    {
        return t - Floor(t / length) * length;
    }
    #endregion


    public static float EaseInQuad(float start, float end, float val)
    {
        end -= start;
        return end * val * val + start;
    }

    public static float EaseInQuart(float start, float end, float val)
    {
        end -= start;
        return end * val * val * val * val + start;
    }


    public static Vector3 EaseInQuad(Vector3 start, Vector3 end, float val)
    {
        end -= start;
        return end * val * val + start;
    }

    public static Vector3 EaseInQuart(Vector3 start, Vector3 end, float val)
    {
        end -= start;
        return end * val * val * val * val + start;
    }

    public static float Vector2Angle(float x1, float y1, float x2, float y2)
    {
        var disX = x1 - x2;
        var disY = y1 - y2;
        if (disY > 0)
        {
            return Atan(disX / disY)*Rad2Deg+180;
        } 
        return Atan(disX / disY)*Rad2Deg;
    }

    public static float Vector2Angle(Vector2 v1, Vector2 v2)
    {
        float disX = v1.x - v2.x;
        float disY = v1.y - v2.y;
        if (disY == 0)
        {
            if (disX >= 0)
            {
                return -90;
            }
            return 90;
        }
        float angle = Atan(disX / disY) * Rad2Deg;
        if (disY>0)
        {
            return angle + 180;
        }
        return angle;
    }
}
